home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Dave’s Fab Samples ƒ / DavesFabSamples.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  16.8 KB  |  537 lines  |  [TEXT/KAHL]

  1. /******************************************************************************\
  2. *
  3. * Apple Macintosh Developer Technical Support
  4. *
  5. * Main program file
  6. *
  7. * Program: DavesFabSamples
  8. * File:    DavesFabSamples.c
  9. *
  10. * by:      Forrest Tanaka
  11. *
  12. * Copyright © 1988-1994 Apple Computer, Inc.
  13. * All rights reserved.
  14. *
  15. \******************************************************************************/
  16.  
  17.  
  18. /******************************************************************************\
  19. * Header Files
  20. \******************************************************************************/
  21.  
  22. #include <Desk.h>
  23. #include <DiskInit.h>
  24. #include <Errors.h>
  25. #include <Fonts.h>
  26. #include <Menus.h>
  27. #include <Resources.h>
  28. #include <ToolUtils.h>
  29. #include <SegLoad.h>
  30.  
  31. #include <AppleEvents.h>
  32. #include <GestaltEqu.h>
  33. #include <Packages.h>
  34. #include <Traps.h>
  35.  
  36. #include <GXGraphics.h>
  37.  
  38. #include "DavesFabSamples.h"
  39. #include "MenuHandler.h"
  40.  
  41.  
  42. /******************************************************************************\
  43. * Constants
  44. \******************************************************************************/
  45.  
  46. #define kMaxSleepTime 60 /* # ticks willing to wait between minor switches */
  47.  
  48.  
  49. /******************************************************************************\
  50. * Macros
  51. \******************************************************************************/
  52.  
  53. /* Return status of bth bit of m */
  54. #define btst(m,b) ((m) & (1L << (b)))
  55.  
  56.  
  57. /******************************************************************************\
  58. * Global Variables
  59. \******************************************************************************/
  60.  
  61. Boolean gQuitting;       /* True if user requested that this app quit */
  62. Boolean gWereInFront;    /* True if this application is frontmost */
  63. Boolean gFixMenus;       /* True if menus need fixing */
  64. Boolean gHasAppleEvents; /* True if Apple Events implemented */
  65. Boolean gHasCoolSF;      /* True if 7.0 Standard File routines available */
  66.  
  67. AEEventHandlerUPP    gOurAEQuitHandler;        // proc ptr for our event handler
  68.  
  69. #if defined(powerc) || defined(__powerc)
  70.     QDGlobals    qd;
  71. #endif
  72.  
  73.  
  74. /******************************************************************************\
  75. * Private Function Prototypes
  76. \******************************************************************************/
  77.  
  78. int main(void);
  79.  
  80. void StartUp(void);
  81.  
  82. void gxShutDown(void);
  83.  
  84. void EventLoop(void);
  85.  
  86. void DoMouseDown(
  87.     EventRecord *anEvent);
  88.  
  89. void DoKeyDown(
  90.     EventRecord *anEvent);
  91.  
  92. pascal OSErr HandleAEquit(
  93.     AppleEvent *quitAppleEvent,
  94.     AppleEvent *reply,
  95.     long       handlerRefCon);
  96.  
  97. OSErr DoneRequiredParams(
  98.     AppleEvent *anAppleEvent);
  99.  
  100. void DoWindowClose(
  101.     EventRecord *anEvent,
  102.     WindowPtr   eventWindow);
  103.     
  104. void Exception (
  105.     long msgType,
  106.     long msgCode);
  107.  
  108.  
  109.  
  110. /******************************************************************************\
  111. * Public: main - Entry gxPoint to this application
  112. *
  113. * After the gxHeap is initialized by allocating several master pointer blocks and
  114. * expanding the application’s gxHeap to its maximum size, StartUp is called to
  115. * complete initialization.  Then the main event loop is entered, and that’s
  116. * where we stay until the user chooses Quit.
  117. \******************************************************************************/
  118.  
  119. int main()
  120. {
  121.     MaxApplZone();                    /* Prepare the gxHeap */
  122.     MoreMasters(); MoreMasters();
  123.     MoreMasters(); MoreMasters();
  124.     MoreMasters(); MoreMasters();
  125.     MoreMasters(); MoreMasters();
  126.  
  127.     StartUp();                        /* gxInitialize the application */
  128.     EventLoop();                    /* Execute the main event loop */
  129.     gxShutDown();                    /* Shut down the application */
  130.     
  131.     return 0;                        /* Return the ANSI way */
  132. }
  133.  
  134.  
  135. /******************************************************************************\
  136. * StartUp - Do whatever has to be done to gxInitialize the application
  137. *
  138. * This routine is called after the gxHeap is initialized to gxInitialize the
  139. * application.  This involves initializing the toolbox, emergency memory,
  140. * loading up the menus, validating the current environment, and initializing
  141. * global variables.  If any errors occur while doing this, StartUp displays
  142. * an alert telling the user what the error was and then ExitToShell is called.
  143. * This is an unusual way to react to errors, and I only do it here because it’s
  144. * so early in execution that there really isn’t much else that can be done.
  145. *
  146. * See EmergMem.h in this application for details about emergency memory.
  147. \******************************************************************************/
  148.  
  149. static void StartUp()
  150. {
  151.     short        result;  /* Result of alert; ignored */
  152.     long         aeAttrs; /* AppleEvent attributes */
  153.     long         sfAttrs; /* Standard File attributes */
  154.     OSErr        error;
  155.     long         msgType;
  156.     long         msgCode;
  157.  
  158.     /* gxInitialize Sarano */
  159.     GXEnterGraphics();
  160.  
  161.     /* gxInitialize the toolbox */
  162.     InitGraf( &qd.thePort );
  163.     InitFonts();
  164.     InitWindows();
  165.     InitMenus();
  166.     TEInit();
  167.     InitDialogs( nil );
  168.  
  169.     /* gxInitialize emergency memory */
  170.  
  171.     /* gxInitialize the menus */
  172.     error = StartMenus();
  173.     
  174.     if (error == memFullErr)        Exception( rMemErrMessages, kMemErrAppOpenMsg );
  175.     else if (error == resNotFound)    Exception( rResErrMessages, kResErrAppDamageMsg );
  176.     else if (error == dsSysErr)        Exception( rMiscErrMessages, kMiscErrUnknownMsg );
  177.  
  178.  
  179.     /* Check for the fancier capabilities */
  180.     
  181.     error = Gestalt( gestaltAppleEventsAttr, /*<*/&aeAttrs );
  182.     if (error != noErr)
  183.         gHasAppleEvents = false;
  184.     else
  185.         gHasAppleEvents = btst( aeAttrs, gestaltAppleEventsPresent );
  186.         
  187.     error = Gestalt( gestaltStandardFileAttr, /*<*/&sfAttrs );
  188.     if (error != noErr)
  189.         gHasCoolSF = false;
  190.     else
  191.         gHasCoolSF = btst( sfAttrs, gestaltStandardFile58 );
  192.  
  193.     /* Install the AppleEvent handler */
  194.     if (gHasAppleEvents)
  195.     {
  196.         gOurAEQuitHandler = NewAEEventHandlerProc(HandleAEquit);
  197.         
  198.         error = AEInstallEventHandler( kCoreEventClass,
  199.                                         kAEQuitApplication,
  200.                                         gOurAEQuitHandler, 0, false );
  201.                                         
  202.         if (error == memFullErr)    Exception( rMemErrMessages, kMemErrAppOpenMsg );
  203.         else if (error != noErr)    Exception( rMiscErrMessages, kMiscErrUnknownMsg );
  204.     }
  205. }
  206.  
  207.  
  208. /******************************************************************************\
  209. * gxShutDown - Do whatever has to be done to shut down the application
  210. *
  211. * This routine is called when the application is about to shut down.  It calls
  212. * GXExitGraphics to shut down Sarano graphics.
  213. \******************************************************************************/
  214.  
  215. static void gxShutDown()
  216. {
  217.     DisposeRoutineDescriptor(gOurAEQuitHandler); // dispose our routine descriptor
  218.     GXExitGraphics();
  219. }
  220.  
  221.  
  222. /******************************************************************************\
  223. * EventLoop - Main event loop for this application
  224. *
  225. * This is the main event loop of this application.  During every iteration of
  226. * the event loop, the menus are kept up-to-date.  Also, NoEmergMem is called to
  227. * detect whether the emergency memory was used.  If it was, then RecoverEmergMem
  228. * is called in an attept to get it back.  If it can’t, then some commands could
  229. * be disabled until the memory can be recovered.
  230. \******************************************************************************/
  231.  
  232. static void EventLoop()
  233. {
  234.     EventRecord anEvent;    /* An incoming event */
  235.     WindowPtr   lastWindow; /* Pointer to front window during last iteration */
  236.     WindowPtr   currWindow; /* Pointer to the current front window */
  237.  
  238.     gWereInFront = true;
  239.     gQuitting = false;
  240.     gFixMenus = true;
  241.     lastWindow = nil;
  242.     
  243.     InitCursor();
  244.  
  245.     /* We loop until gQuitting is true */
  246.     
  247.     while (!gQuitting)
  248.     {
  249.         /* Fix the menus to reflect current conditions */
  250.         currWindow = FrontWindow();
  251.         if (currWindow != lastWindow || gFixMenus)
  252.         {
  253.             FixMenus();
  254.             lastWindow = currWindow;
  255.             gFixMenus = false;
  256.         }
  257.  
  258.         /* It’s time to get and examine an event */
  259.         
  260.         if ( WaitNextEvent( everyEvent, &anEvent, kMaxSleepTime, nil ) )
  261.         {
  262.             switch (anEvent.what)
  263.             {
  264.                 case mouseDown:
  265.                     DoMouseDown( &anEvent );
  266.                     break;
  267.                     
  268.                 case keyDown:
  269.                 case autoKey:
  270.                     DoKeyDown( &anEvent );
  271.                     break;
  272.                     
  273.                 case updateEvt:
  274.                     DoUpdateEvt( &anEvent );
  275.                     break;
  276.                     
  277.                 case kHighLevelEvent:
  278.                     (void)AEProcessAppleEvent( &anEvent );
  279.                     break;
  280.             }
  281.         }
  282.     }
  283. }
  284.  
  285.  
  286. /******************************************************************************\
  287. * DoMouseDown - Mouse-down event dispatcher
  288. *
  289. * When a mouseDown event is received in the main event loop, this routine is
  290. * called to determine which area on the screens the mouseDown was, and to
  291. * dispatch to the appropriate routine to handle mouseDown events in that area.
  292. * The mouseDown event is passed in the anEvent parameter.
  293. *
  294. * See MenuHandler.h for routines that handle mouse-down events in the menu bar.
  295. \******************************************************************************/
  296.  
  297. static void DoMouseDown(
  298.     EventRecord *anEvent) /* Contains mouse-down event */
  299. {
  300.     short     clickArea;   /* Area of the screen that was clicked */
  301.     WindowPtr eventWindow; /* Pointer the clicked window, if any */
  302.  
  303.     /* Find clicked area of screen or window */
  304.     clickArea = FindWindow( anEvent->where, /*<*/&eventWindow );
  305.  
  306.     /* Jump to mouseDown-handling routine appropriate for screen area */
  307.     switch (clickArea)
  308.     {
  309.         case inMenuBar:
  310.             DoMenuChoice( MenuSelect( anEvent->where ) );
  311.             break;
  312.         case inGoAway:
  313.             DoWindowClose( anEvent, eventWindow );
  314.             break;
  315.         default:
  316.             break;
  317.     }
  318. }
  319.  
  320.  
  321. /******************************************************************************\
  322. * DoKeyDown - Key-down event dispatcher
  323. *
  324. * When a keyDown or autoKey event is received in the main event loop, this
  325. * routine is called to determine whether key is a command-key equivalent for a
  326. * menu item or not.  If the command key isn’t down, then the key stroke is
  327. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  328. * of the menu item that corresponds to the command key, if any.  Then
  329. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  330. * menu item.  The keyDown or autoKey event is passed in anEvent.
  331. \******************************************************************************/
  332.  
  333. static void DoKeyDown(
  334.     EventRecord *anEvent) /* Contains the key-down event */
  335. {
  336.     char theKey; /* ASCII code of key that was pressed */
  337.  
  338.     /* Get the ASCII code of the pressed key */
  339.     theKey = anEvent->message & charCodeMask;
  340.  
  341.     /* If anEvent was keyDown and command key was down, it’s menu command */
  342.     if (anEvent->what == keyDown && (anEvent->modifiers & cmdKey))
  343.         DoMenuChoice( MenuKey( theKey ) );
  344. }
  345.  
  346.  
  347. /******************************************************************************\
  348. * Private: DoWindowClose - Handle a click in the close box of a window
  349. *
  350. * This routine should be called when the user clicks in the close box of the
  351. * window specified by eventWind.  The mouse is tracked until the user releases
  352. * the mouse button.  If the user released the mouse button while the mouse was
  353. * in the close box, then DisposeWindow is called to close the window.  anEvent
  354. * contains the mouse-down event that was determined to be a mouse click in the
  355. * window.
  356. \******************************************************************************/
  357.  
  358. static void DoWindowClose(
  359.     EventRecord *anEvent,    /* Mouse-down event in the close box */
  360.     WindowPtr   eventWindow) /* Pointer to the window that was clicked */
  361. {
  362.     if (TrackGoAway( eventWindow, anEvent->where ))
  363.         DisposeWindow( eventWindow );
  364. }
  365.  
  366.  
  367. /******************************************************************************\
  368. * Private: HandleAEquit - Handler for 'quit' AppleEvent
  369. *
  370. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  371. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  372. * called which causes this application to quit at the start of the next
  373. * iteration of the main event loop.
  374. *
  375. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  376. * to do in reaction to any AppleEvent is to check to see if there are any
  377. * required parameters in the AppleEvent that this routine doesn’t recognise.
  378. * DoneRequiredParms checks for this condition and returns an error if there are
  379. * in fact required parameters in the AppleEvent or if some other error occurs
  380. * during the check.
  381. \******************************************************************************/
  382.  
  383. static pascal OSErr HandleAEquit(
  384.     AppleEvent *quitAppleEvent, /* Contains the ‘quit’ AppleEvent */
  385.     AppleEvent *reply,          /* Returns reply; ignored */
  386.     long       handlerRefCon)   /* Application-defined parameter; ignored */
  387. {
  388. #pragma unused(reply,handlerRefCon)
  389.     OSErr error;
  390.  
  391.     /* quit AE has no parms, but check in case the client requires any */
  392.     error = DoneRequiredParams( quitAppleEvent );
  393.     
  394.     if (error == noErr)
  395.         /* No extra parameters; handle Quit command */
  396.         DoQuit();
  397.  
  398.     return error;
  399. }
  400.  
  401.  
  402. /******************************************************************************\
  403. * DoneRequiredParams - Done processing required params; OK?
  404. *
  405. * DoneRequiredParams checks to see if the AppleEvent specified by the
  406. * anAppleEvent parameter has any required parameters that we haven’t yet
  407. * processed.  If there aren’t any left, then noErr is returned.  If there are
  408. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  409. * is returned.  If any other errors occur, then that error code is returned.
  410. \******************************************************************************/
  411.  
  412. static OSErr DoneRequiredParams(
  413.     AppleEvent *anAppleEvent) /* AppleEvent being checked */
  414. {
  415.     DescType typeCode;   /* Type of AppleEvent attribute found; ignored */
  416.     Size     actualSize; /* Actual size of parameters; ignored */
  417.     OSErr    error;
  418.  
  419.     /* Are there any required parameters in AppleEvent we didn’t process? */
  420.     
  421.        error = AEGetAttributePtr(
  422.                anAppleEvent,
  423.             keyMissedKeywordAttr,
  424.             typeWildCard,
  425.             &typeCode,
  426.             nil,
  427.             0,
  428.             &actualSize );
  429.             
  430.     if (error == errAEDescNotFound)
  431.         /* No required parameters left, so no error */
  432.         error = noErr;
  433.     else if (error == noErr)
  434.         /* There was at least one required parameter we didn’t process */
  435.         error = errAEEventNotHandled;
  436.  
  437.     return error;
  438. }
  439.  
  440.  
  441. /******************************************************************************\
  442. * Public: DoQuit
  443. *
  444. * Each open window is checked to see what kind it is, and then it is closed
  445. * appropriately.
  446. \******************************************************************************/
  447.  
  448. void DoQuit()
  449. {
  450.     WindowPtr aWindow; /* Pointer to each window in the window list */
  451.  
  452.     aWindow = FrontWindow();
  453.  
  454.     /* Keep closing a window until there are no windows left */
  455.     while (aWindow != nil)
  456.     {
  457.         DisposeWindow( aWindow );
  458.         aWindow = FrontWindow();
  459.     }
  460.  
  461.     /* Tell the main event loop that we’re done */
  462.     gQuitting = true;
  463. }
  464.  
  465.  
  466. /******************************************************************************\
  467. * Public: DoUpdateEvt
  468. *
  469. * As new kinds of windows are added to this application, this routine will have
  470. * to be able to detect the new kind of window and dispatch to the routine that
  471. * handles update events in that kind of window.
  472. \******************************************************************************/
  473.  
  474. void DoUpdateEvt(
  475.     EventRecord *anEvent) /* Update event */
  476. {
  477.     WindowPtr eventWindow; /* Pointer to the window to update */
  478.  
  479.     /* Get a pointer to the window that needs an update */
  480.     eventWindow = (WindowPtr)anEvent->message;
  481.  
  482.     /* Update the window that needs it */
  483.     SetPort( eventWindow );
  484.     BeginUpdate( eventWindow );
  485.     EndUpdate( eventWindow );
  486. }
  487.  
  488.  
  489. /******************************************************************************\
  490. * Public: ShowAlert
  491. *
  492. * To position the alert before it’s displayed, the ALRT resource is loaded
  493. * before it’s displayed, and its boundsRect is put into the proper position
  494. * through the CenterScreenRect routine.  Because this modifies the ALRT
  495. * resource in memory and because ALRT resources are normally purgeable, it must
  496. * be made unpurgeable until the alert is dismissed.
  497. \******************************************************************************/
  498.  
  499. short ShowAlert(
  500.     short alertType,    /* Type of alert to display */
  501.     short buttonOption, /* Button options for alert */
  502.     short messageClass, /* Class of message to display in alert */
  503.     short messageIndex) /* Index of message to display in alert */
  504. {
  505.     short        itemHit;     /* Item number of clicked item */
  506.     Str255        aMessage;
  507.  
  508.     /* Put the specified message into the dialog parameter text */
  509.     if (messageIndex != 0)
  510.     {
  511.         GetIndString( aMessage, messageClass, messageIndex );
  512.         ParamText( aMessage, "\P", "\P", "\P" );
  513.     }
  514.  
  515.     /* Show the stop alert */
  516.     InitCursor();
  517.  
  518.     /* Present the alert */
  519.     if (alertType == kGenericAlert)            itemHit = Alert( buttonOption, nil );
  520.     else if (alertType == kNoteAlert)        itemHit = NoteAlert( buttonOption, nil );
  521.     else if (alertType == kCautionAlert)    itemHit = CautionAlert( buttonOption, nil );
  522.     else if (alertType == kStopAlert)        itemHit = StopAlert( buttonOption, nil );
  523.  
  524.     return itemHit;
  525. }
  526.  
  527.  
  528. /******************************************************************************\
  529. * Exception - Signal that an exception has occured and exit
  530. \******************************************************************************/
  531.  
  532. void Exception ( long msgType, long msgCode)
  533. {
  534.     ShowAlert( kStopAlert, rOKAlertID, msgType, msgCode );
  535.     ExitToShell();
  536. }
  537.